package cn.faster.config.security.shiro;

import cn.faster.config.cache.RedisCacheManger;
import cn.faster.common.enums.ShiroEnum;
import cn.faster.config.security.shiro.realm.UserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.support.DelegatingSubject;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;

/**
 * description: ShiroConfig
 * date: 2021/6/9 10:02
 * author: XiaoCoder
 * version: 1.0
 */
@Configuration
public class ShiroConfig {

    @Bean
    public Subject getSubject(@Qualifier("securityManager") SecurityManager securityManager) {
        return new DelegatingSubject(securityManager);
    }

    @Bean(value = "securityManager")
    public DefaultWebSecurityManager getDefaultSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(userRealm);
        ThreadContext.bind(defaultWebSecurityManager);
        return defaultWebSecurityManager;
    }

    @Bean(value = "userRealm")
    public UserRealm getUserRealm() {
        UserRealm userRealm = new UserRealm();
        // 修改凭证校验匹配器
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName((String) ShiroEnum.XIAO_HASHALGORITHM.getValue());
        hashedCredentialsMatcher.setHashIterations((Integer) ShiroEnum.XIAO_HASHITERATIONS.getValue());
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        userRealm.setAuthenticationCachingEnabled(true);//开启认证缓存
        userRealm.setCacheManager(new RedisCacheManger()); // 开启缓存管理
        userRealm.setCachingEnabled(true);// 开启全局缓存
        userRealm.setAuthorizationCachingEnabled(true);// 授权缓存开启

        return userRealm;
    }

    /**
     * 配置shiro过滤器
     *
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
        System.out.println("shiroConfiguration.shiroFilter()");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 配置拦截器
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 配置拦截
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/login", "authc");
        // 配置不会拦截的链接
        filterChainDefinitionMap.put("/**", "anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }


    /**
     * 开启shiro注解支持
     * 使用代理的方式；所以需要开启代码支持
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }


}
